package com.hxx.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class QinwenController {

    @Autowired
    private ChatModel chatModel;
    @Autowired
    private ObjectMapper objectMapper;
    //记忆
    private InMemoryChatMemory memory = new InMemoryChatMemory();

    /**
     * 处理GET请求的聊天接口
     *
     * 该方法使用预定义的聊天模型来响应用户的聊天请求它通过传入用户的消息作为提示来生成回复
     * 主要涉及与ChatClient的交互，利用其prompt方法构建聊天提示，调用call方法生成回复，并提取回复的内容
     *
     * @param prompt 用户发送的聊天消息，作为聊天模型的输入提示
     * @return 聊天模型生成的回复内容
     */
    @GetMapping("/chat")
    public String chat(String prompt){
        // 创建ChatClient实例，用于与聊天模型交互
        ChatClient chatClient = ChatClient.create(chatModel);
        // 使用ChatClient实例的prompt方法开始构建聊天提示，通过user方法添加用户消息，call方法发送提示并接收回复，最后提取回复的内容返回
        return chatClient.prompt()
                .user(prompt)
                .call()
                .content();
    }

    /**
     * 处理聊天流请求
     * 该方法使用Server-Sent Events (SSE)技术，允许服务器向客户端推送实时更新
     * 在这种情况下，它用于创建一个聊天流，其中服务器根据用户的提示实时生成消息
     *
     * @param prompt 用户的输入提示，用于生成聊天响应
     * @return 返回一个Flux对象，该对象会生成一系列ServerSentEvent，每个事件包含一个聊天响应
     */
    @GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> chatSSE(String prompt,String sessionId){
        var advice = new MessageChatMemoryAdvisor(memory,sessionId,10);
        // 创建一个ChatClient实例，用于与聊天模型进行交互
        // 这里体现了函数式编程的思想，通过链式调用构建复杂的交互逻辑
        return ChatClient.create(chatModel)
                .prompt()
                .user(prompt)
                .advisors(advice)
                .stream()
                .chatResponse()
                // 将每个聊天响应映射为一个ServerSentEvent对象
                // 使用map函数进行流的转换，体现了函数式编程的转换操作
                .map(chatResponse -> ServerSentEvent.<String>builder(toJson(chatResponse))
                        .event("message")
                        .build());
    }

    @SneakyThrows
    public String toJson(ChatResponse chatResponse) {
        try {
            return objectMapper.writeValueAsString(chatResponse);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
